﻿@using System.Net.Http.Headers
@using System.Text
@using System.Text.RegularExpressions
@using Polly
@using Tool.Services
@inject IHttpClientFactory httpClientFactory
@inject InstanceService instanceService
@inject ISnackbar snackbar
@inject IJSRuntime javaScript
@inject IServiceProvider serviceProvider
<MudText Typo="Typo.h6">导出表结构</MudText>
<MudSpacer />
<MudGrid>
	<MudItem xs="3">
		<MudSelect @bind-Value="_selectedInstance" Label="选择实例" SelectedValuesChanged="(IEnumerable<string> instances) => OnInstanceSeletected(instances)" Variant="Variant.Text" Clearable Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.LocationOn">
			@foreach (var instance in _intances)
			{
				<MudSelectItem Value="@instance">@instance</MudSelectItem>
			}
		</MudSelect>

	</MudItem>
	<MudItem xs="3">
		<MudSelect @bind-Value="_selectedDatabase" Label="选择库" SelectedValuesChanged="(IEnumerable<string> instances) => OnDatabaseSelected(instances)" Variant="Variant.Text" Clearable Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.LocationOn">
			@foreach (var database in _databases)
			{
				<MudSelectItem Value="@database">@database</MudSelectItem>
			}
		</MudSelect>

	</MudItem>
	<MudItem xs="3">
		@* <MudSelect @bind-Value="_selectedTable" Label="选择表" Variant="Variant.Text" Clearable Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.LocationOn">
			@foreach (var table in _tables)
			{
				<MudSelectItem Value="@table">@table</MudSelectItem>
			}
		</MudSelect> *@
		<MudTextField @bind-Value="_selectedTable" Label="表名" Variant="Variant.Text" Adornment="Adornment.Start"
					  AdornmentIcon="@Icons.Material.Filled.LockPerson" Clearable="true" />

	</MudItem>
	<MudItem xs="1">
		<MudTextField @bind-Value="_tableCount" Label="最大分表数量" Variant="Variant.Text" Adornment="Adornment.Start"
					  AdornmentIcon="@Icons.Material.Filled.Numbers" Clearable="true" />
	</MudItem>
	<MudItem xs="2">
		<MudButton Class="align-self-center" FullWidth="true" Disabled="@_processing" OnClick="GetDescriptions" Variant="Variant.Filled" Color="Color.Primary">
			@if (_processing)
			{
				<ProgressBar CurrentValue="@_progress" MaxValue="@_totalCount"></ProgressBar>
				<MudText Class="ms-2">Processing</MudText>
			}
			else
			{
				<MudText>获取表结构</MudText>
			}
		</MudButton>
	</MudItem>



</MudGrid>

@code {
	private List<string> _intances = new List<string>();
	private List<string> _databases = new List<string>();
	private List<string> _tables = new List<string>();
	private string _selectedInstance;
	private string _selectedDatabase;
	private string _selectedTable;
	private bool _processing = false;
	private int _tableCount = 1;
	private int _progress = 0;
	private int _totalCount = 0;

	private Regex _tableIndex = new Regex(@"(.*?)_(\d+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);

	[Parameter]
	public string SelectedSite { get; set; }
	[Parameter]
	public HttpResponseHeaders ResponseHeaders { get; set; }


	protected override async Task OnParametersSetAsync()
	{
		await base.OnParametersSetAsync();

		try
		{
			_intances = await instanceService.GetInstances(SelectedSite, ResponseHeaders);
		}
		catch (Exception ex)
		{
			snackbar.Add($"获取数据库实例异常:{ex.Message}", Severity.Error);
		}
	}
	private async Task OnInstanceSeletected(IEnumerable<string> instances)
	{
		try
		{
			_databases = await instanceService.GetDatabases(_selectedInstance, SelectedSite, ResponseHeaders);
		}
		catch (Exception ex)
		{
			snackbar.Add($"获取数据库异常:{ex.Message}", Severity.Error);
		}
	}

	private async Task OnDatabaseSelected(IEnumerable<string> databases)
	{
		try
		{
			_tables = await instanceService.GetTables(_selectedInstance, _selectedDatabase, SelectedSite, ResponseHeaders);
			_totalCount = _tables.Count;
		}
		catch (Exception ex)
		{
			snackbar.Add($"获取表异常:{ex.Message}", Severity.Error);
		}
	}

	private async Task GetDescriptions()
	{
		try
		{
			if (string.IsNullOrWhiteSpace(_selectedInstance) || string.IsNullOrWhiteSpace(_selectedDatabase))
			{
				snackbar.Add("请先选择实例和数据库", Severity.Warning);
				return;
			}
			_processing = true;
			_progress = 0;
			var pipeline = serviceProvider.GetRequiredKeyedService<ResiliencePipeline>("my-pipeline");

			if (string.IsNullOrWhiteSpace(_selectedTable))
			{
				var sb = new StringBuilder(_tables.Count * 1000);
				string firstSql = string.Empty;
				foreach (var table in _tables)
				{
					var matched = _tableIndex.Match(table);
					if (matched.Success)
					{
						var tableIndex = int.Parse(matched.Groups[2].Value);
						if (tableIndex >= _tableCount)
						{
							_progress++;
							StateHasChanged();
							continue;
						}
						else
						{
							if (tableIndex == 0)
							{
								firstSql = string.Empty;
								var createSql = await pipeline.ExecuteAsync(async ct =>
								{
									return await instanceService.GetTableStructs(_selectedInstance, _selectedDatabase, table, SelectedSite, ResponseHeaders, _tables);
								}, CancellationToken.None);
								// var createSql = await instanceService.GetTableStructs(_selectedInstance, _selectedDatabase, table, SelectedSite, ResponseHeaders, _tables);
								if (!string.IsNullOrWhiteSpace(createSql))
								{
									if (_progress != 0)
									{
										sb.Append(";");
										sb.Append(Environment.NewLine);
									}

									sb.Append(createSql);
									firstSql = createSql;
								}
							}
							else
							{
								var sql = firstSql.Replace($"{matched.Groups[1]}_0", $"{matched.Groups[1]}_{tableIndex}");
								if (_progress != 0)
								{
									sb.Append(";");
									sb.Append(Environment.NewLine);
								}

								sb.Append(sql);
							}
						}
					}
					else
					{
						firstSql = string.Empty;
						var createSql = await pipeline.ExecuteAsync(async ct =>
								{
									return await instanceService.GetTableStructs(_selectedInstance, _selectedDatabase, table, SelectedSite, ResponseHeaders, _tables);
								}, CancellationToken.None);
						// var createSql = await instanceService.GetTableStructs(_selectedInstance, _selectedDatabase, table, SelectedSite, ResponseHeaders, _tables);
						if (!string.IsNullOrWhiteSpace(createSql))
						{
							if (_progress != 0)
							{
								sb.Append(";");
								sb.Append(Environment.NewLine);
							}

							sb.Append(createSql);
						}

						// await Task.Delay(1000);
					}
					_progress++;
					StateHasChanged();
				}
				sb.Append(";");
				var bytes = Encoding.UTF8.GetBytes(sb.ToString());
				var fileName = $"{_selectedDatabase}.sql";

				await javaScript.InvokeVoidAsync("downloadFileFromBytes", bytes, fileName, "application/zip");
			}
			else
			{
				var sb = new StringBuilder(_tableCount * 1000);
				_totalCount = _tableCount;
				var matched = _tableIndex.Match(_selectedTable);
				var tableName = _selectedTable;
				if (matched.Success)
				{
					tableName = matched.Groups[1].Value;
				}
				var firstSql = string.Empty;
				for (int i = 0; i < _tableCount; i++)
				{
					if (i == 0)
					{
						var createSql = await pipeline.ExecuteAsync(async ct =>
						{
							return await instanceService.GetTableStructs(_selectedInstance, _selectedDatabase, $"{tableName}_{i}", SelectedSite, ResponseHeaders, _tables);
						}, CancellationToken.None);
						if (createSql.IsNullOrEmpty())
						{
							break;
						}
						firstSql = createSql;
						sb.Append(firstSql);
					}
					else
					{
						var sql = firstSql.Replace($"{tableName}_0", $"{tableName}_{i}");
						sb.Append(sql);
					}
					
					sb.Append(";");
					sb.Append(Environment.NewLine);
					_progress++;
					StateHasChanged();
				}

				// var createSql = await instanceService.GetTableStructs(_selectedInstance, _selectedDatabase, _selectedTable, SelectedSite, ResponseHeaders, _tables);
				var bytes = Encoding.UTF8.GetBytes(sb.ToString());
				var fileName = $"{_selectedTable}.sql";
				await javaScript.InvokeVoidAsync("downloadFileFromBytes", bytes, fileName, "application/zip");
			}
		}
		catch (HttpRequestException httpEx)
		{
			// 专门捕获 HTTP 层异常，可能包含内部异常
			Console.WriteLine($"HTTP 请求异常: {httpEx.Message}");
			if (httpEx.InnerException != null)
			{
				Console.WriteLine($"内部异常: {httpEx.InnerException.Message}");
				// 这里可能会看到 "The credentials supplied to the package were not recognized"
			}
		}
		catch (Exception ex)
		{
			Console.WriteLine($"发生错误: {ex.Message}");

		}
		finally
		{
			_processing = false;
		}
	}
}